package com.simple.car.loader.server.parser;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.simple.car.loader.server.annotation.Function;
import com.simple.car.loader.server.annotation.Loader;
import com.simple.car.loader.server.annotation.RequestParam;
import com.simple.car.loader.server.entity.Apply;
import com.simple.car.loader.server.parser.impl.BooleanParser;
import com.simple.car.loader.server.parser.impl.ByteParser;
import com.simple.car.loader.server.parser.impl.CharParser;
import com.simple.car.loader.server.parser.impl.DoubleParser;
import com.simple.car.loader.server.parser.impl.FloatParser;
import com.simple.car.loader.server.parser.impl.IntegerParser;
import com.simple.car.loader.server.parser.impl.LongParser;
import com.simple.car.loader.server.parser.impl.ShortParser;
import com.simple.car.loader.server.parser.impl.StringParser;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Function
public class AutoFind implements Finder {

    private Gson gson = new Gson();

    @Loader
    private AutoParser autoParser;

    private final List<Class<?>> classes = new ArrayList<>(
            Arrays.asList(
                    byte.class, short.class, char.class, int.class, long.class, float.class, double.class, boolean.class,
                    Byte.class, Short.class, Character.class, Integer.class, Long.class, Float.class, Double.class, Boolean.class,
                    String.class
            )
    );

    @Override
    public Object[] find(Socket socket, Apply apply, Method method) {
        Parameter[] parameters = method.getParameters();
        if (parameters.length == 0) {
            return null;
        }
        List<Object> objects = new ArrayList<>();
        byte[] data = apply.getData();
        String json = new String(data, StandardCharsets.UTF_8);
        Map<String, Object> map = gson.fromJson(json, new TypeToken<HashMap<String, Object>>() {
        }.getType());
        for (Parameter parameter : parameters) {
            Class<?> type = parameter.getType();
            if (type.isInstance(socket)) {
                objects.add(socket);
                continue;
            }
            RequestParam requestParam = parameter.getDeclaredAnnotation(RequestParam.class);
            if (requestParam == null) {
                throw new IllegalArgumentException(String.format("缺少必要的注解：%s", RequestParam.class.getName()));
            }
            if (classes.contains(type)) {
                Object o = map.get(requestParam.value());
                if (requestParam.necessary()) {
                    if (o == null) {
                        throw new IllegalArgumentException(String.format("参数：%s 不能为null", requestParam.value()));
                    }
                }
                Class<Parser> clazz;
                clazz = (Class<Parser>) findClass(type);
                if (clazz == null) {
                    clazz = requestParam.type();
                }
                objects.add(autoParser.parser(o, clazz));
            } else {
                Object o = gson.fromJson(json, type);
                if (requestParam.necessary()) {
                    if (o == null) {
                        throw new IllegalArgumentException(String.format("参数：%s 不能为null", requestParam.value()));
                    }
                }
                objects.add(o);
            }
        }
        return objects.toArray();
    }

    private Class<?> findClass(Class<?> clazz) {
        if (byte.class.equals(clazz) || Byte.class.equals(clazz)) {
            return ByteParser.class;
        } else if (short.class.equals(clazz) || Short.class.equals(clazz)) {
            return ShortParser.class;
        } else if (char.class.equals(clazz) || Character.class.equals(clazz)) {
            return CharParser.class;
        } else if (int.class.equals(clazz) || Integer.class.equals(clazz)) {
            return IntegerParser.class;
        } else if (long.class.equals(clazz) || Long.class.equals(clazz)) {
            return LongParser.class;
        } else if (float.class.equals(clazz) || Float.class.equals(clazz)) {
            return FloatParser.class;
        } else if (double.class.equals(clazz) || Double.class.equals(clazz)) {
            return DoubleParser.class;
        } else if (boolean.class.equals(clazz) || Boolean.class.equals(clazz)) {
            return BooleanParser.class;
        } else if (String.class.equals(clazz)) {
            return StringParser.class;
        }
        return null;
    }
}
